package com.artezio.task.dao.impl;

import com.artezio.task.dao.ContactsDao;
import com.artezio.task.model.Contact;
import com.artezio.task.model.ContactTelDetail;
import org.hibernate.Criteria;
import org.hibernate.Hibernate;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.*;
import org.hibernate.transform.DistinctRootEntityResultTransformer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.expression.spel.ast.Projection;
import org.springframework.stereotype.Repository;

import javax.persistence.criteria.CriteriaBuilder;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;


@Repository
public class ContactsDaoImpl implements ContactsDao {

    @Autowired
    private SessionFactory sessionFactory;

    @Override
    public void addNewContact(Contact contact) {
        sessionFactory.getCurrentSession().save(contact);
    }

    @Override
    public void saveContact(Contact contact) {
        sessionFactory.getCurrentSession().update(contact);
    }

    @Override
    public List<Contact> getAllContacts() {
        Session session = sessionFactory.getCurrentSession();
        Criteria criteria = session.createCriteria(Contact.class);
//        Criteria criteriaDet = session.createCriteria(ContactTelDetail.class);
//        criteria.createAlias("contactTelDetails", "contactTelDetails").addOrder(Order.asc("contactTelDetails.telType"));
        //       criteria.createAlias("contactTelDetails", "contactTelDetails");
        criteria.setResultTransformer(DistinctRootEntityResultTransformer.INSTANCE);
        List<Contact> contacts = criteria.list();
        sort(contacts);


        return contacts;
    }

    @Override
    public Contact findContactById(int id) {
        //String id_str = id+"";
        Criteria crit = sessionFactory.getCurrentSession().createCriteria(Contact.class);
        Criterion idEq = Restrictions.eq("id", id);
        crit.add(idEq);
        Contact contact = (Contact) crit.uniqueResult();
        Hibernate.initialize(contact.getContactTelDetails());
        return contact;
    }


    @Override
    public void deleteContactById(int id) {
        Session session = sessionFactory.getCurrentSession();

        Criterion idEq = Restrictions.eq("id", id);
        Criteria crit = session.createCriteria(Contact.class);
        crit.add(idEq);
        Contact contact = (Contact) crit.uniqueResult();

        session.delete(contact);


    }

    @Override
    public void deleteContact(Contact contact) {
        Session session = sessionFactory.getCurrentSession();

        session.delete(contact);
    }


    @Override
    public List<Contact> getContactsByCriteria(String firstName, String lastName, String telType, String telNumber) {
        Session session = sessionFactory.getCurrentSession();
        Criterion fN = null;
        Criterion tT = null;
        Criterion lN = null;
        Criterion tN = null;
        Criteria crit = session.createCriteria(Contact.class);
        crit.setResultTransformer(DistinctRootEntityResultTransformer.INSTANCE);
        crit.addOrder(Order.asc("contactTelDetails.telType"));
        //criteria.addOrder(Order.asc("field"));
        if (!telType.isEmpty()) {
            tT = Restrictions.ilike("contactTelDetails.telType", telType, MatchMode.ANYWHERE);
            crit.add(tT);
        }
        if (!firstName.isEmpty()) {
            fN = Restrictions.ilike("firstName", firstName, MatchMode.ANYWHERE);
            crit.add(fN);
        }
        if (!lastName.isEmpty()) {
            lN = Restrictions.ilike("lastName", lastName, MatchMode.ANYWHERE);
            crit.add(lN);
        }
        if (!telNumber.isEmpty()) {
            tN = Restrictions.ilike("contactTelDetails.telNumber", telNumber, MatchMode.ANYWHERE);
            crit.add(tN);
        }

        //Criteria criteria = session.createCriteria(Contact.class).createAlias("contactTelDetails", "contactTelDetails").add(Restrictions.ilike("firstName", firstName, MatchMode.ANYWHERE)).add(Restrictions.ilike("lastName",lastName, MatchMode.ANYWHERE)).add(Restrictions.ilike("contactTelDetails.telType",telType,MatchMode.ANYWHERE)).add(Restrictions.ilike("contactTelDetails.telNumber",telNumber,MatchMode.ANYWHERE));


        // List<Contact> contacts = criteria.list();
        List<Contact> contacts = crit.createAlias("contactTelDetails", "contactTelDetails").list();
        sort(contacts);
        return contacts;
    }

    @Override
    public List<Contact> getContactsByCriteriaSortByNameAjax(String firstName, String lastName, String telType, String telNumber, String order) {
        Session session = sessionFactory.getCurrentSession();
        Criterion fN = null;
        Criterion tT = null;
        Criterion lN = null;
        Criterion tN = null;
        Criteria crit = session.createCriteria(Contact.class);
        crit.setResultTransformer(DistinctRootEntityResultTransformer.INSTANCE);

        if (order.equals("nasc")) {
            crit.addOrder(Order.asc("firstName"));
        }
        if (order.equals("ndesc")) {
            crit.addOrder(Order.desc("firstName"));
        }
        //criteria.addOrder(Order.asc("field"));
        if (!telType.isEmpty()) {
            tT = Restrictions.ilike("contactTelDetails.telType", telType, MatchMode.ANYWHERE);
            crit.add(tT);
        }
        if (!firstName.isEmpty()) {
            fN = Restrictions.ilike("firstName", firstName, MatchMode.ANYWHERE);
            crit.add(fN);
        }
        if (!lastName.isEmpty()) {
            lN = Restrictions.ilike("lastName", lastName, MatchMode.ANYWHERE);
            crit.add(lN);
        }
        if (!telNumber.isEmpty()) {
            tN = Restrictions.ilike("contactTelDetails.telNumber", telNumber, MatchMode.ANYWHERE);
            crit.add(tN);
        }

        //Criteria criteria = session.createCriteria(Contact.class).createAlias("contactTelDetails", "contactTelDetails").add(Restrictions.ilike("firstName", firstName, MatchMode.ANYWHERE)).add(Restrictions.ilike("lastName",lastName, MatchMode.ANYWHERE)).add(Restrictions.ilike("contactTelDetails.telType",telType,MatchMode.ANYWHERE)).add(Restrictions.ilike("contactTelDetails.telNumber",telNumber,MatchMode.ANYWHERE));


        // List<Contact> contacts = criteria.list();
        List<Contact> contacts = crit.createAlias("contactTelDetails", "contactTelDetails").list();
        sort(contacts);
        return contacts;
    }

    @Override
    public List<Contact> getContactsByCriteriaSortByLastNameAjax(String firstName, String lastName, String telType, String telNumber, String order) {
        Session session = sessionFactory.getCurrentSession();
        Criterion fN = null;
        Criterion tT = null;
        Criterion lN = null;
        Criterion tN = null;
        Criteria crit = session.createCriteria(Contact.class);
        crit.setResultTransformer(DistinctRootEntityResultTransformer.INSTANCE);

        if (order.equals("lnasc")) {
            crit.addOrder(Order.asc("lastName"));
        }
        if (order.equals("lndesc")) {
            crit.addOrder(Order.desc("lastName"));
        }

        //criteria.addOrder(Order.asc("field"));
        if (!telType.isEmpty()) {
            tT = Restrictions.ilike("contactTelDetails.telType", telType, MatchMode.ANYWHERE);
            crit.add(tT);
        }
        if (!firstName.isEmpty()) {
            fN = Restrictions.ilike("firstName", firstName, MatchMode.ANYWHERE);
            crit.add(fN);
        }
        if (!lastName.isEmpty()) {
            lN = Restrictions.ilike("lastName", lastName, MatchMode.ANYWHERE);
            crit.add(lN);
        }
        if (!telNumber.isEmpty()) {
            tN = Restrictions.ilike("contactTelDetails.telNumber", telNumber, MatchMode.ANYWHERE);
            crit.add(tN);
        }
        //Criteria criteria = session.createCriteria(Contact.class).createAlias("contactTelDetails", "contactTelDetails").add(Restrictions.ilike("firstName", firstName, MatchMode.ANYWHERE)).add(Restrictions.ilike("lastName",lastName, MatchMode.ANYWHERE)).add(Restrictions.ilike("contactTelDetails.telType",telType,MatchMode.ANYWHERE)).add(Restrictions.ilike("contactTelDetails.telNumber",telNumber,MatchMode.ANYWHERE));
        List<Contact> contacts = crit.list();
//        List<Contact> contacts = crit.createAlias("contactTelDetails", "contactTelDetails").list();
        sort(contacts);
        return contacts;
    }

    @Override
    public List<Contact> getContactsByCriteriaPaginAjax(String firstName, String lastName, int maxRes, int firstRes, String order, String sSearch_r) throws UnsupportedEncodingException {

        Session session = sessionFactory.getCurrentSession();
        Criterion fN = null;
//        Criterion tT = null;
        Criterion lN = null;
//        Criterion tN = null;
        Criteria crit = session.createCriteria(Contact.class);
        Integer totalResult = (Integer)crit.setProjection(Projections.rowCount()).uniqueResult();
        int count = totalResult.intValue();
        totalResult=null;
        crit.setProjection(null).setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
//        crit.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);

//         crit.setProjection(Projections.rowCount());
//        Integer count = (Integer)crit.uniqueResult();
//        int c = count.intValue();


        if (order.equals("")) {
            crit.addOrder(Order.desc("lastName"));

        }
        if (order.equals("lnasc")) {
            crit.addOrder(Order.asc("lastName"));
//            crit.setProjection(Projections.distinct(Projections.property("lastName")));
        }
        if (order.equals("lndesc")) {
            crit.addOrder(Order.desc("lastName"));
//            crit.setProjection(Projections.distinct(Projections.property("lastName")));
        }
        if (order.equals("fnasc")) {
            crit.addOrder(Order.asc("firstName"));
//            crit.setProjection(Projections.distinct(Projections.property("firstName")));
        }
        if (order.equals("fndesc")) {
            crit.addOrder(Order.desc("firstName"));
//            crit.setProjection(Projections.distinct(Projections.property("firstName")));
        }

//           crit.setResultTransformer(DistinctRootEntityResultTransformer.INSTANCE);
        //criteria.addOrder(Order.asc("field"));
//        if (!telType.isEmpty()) {
//            tT = Restrictions.ilike("contactTelDetails.telType", telType, MatchMode.ANYWHERE);
//            crit.add(tT);
//        }
//        if (!firstName.isEmpty()) {
//            fN = Restrictions.ilike("firstName", firstName, MatchMode.ANYWHERE);
//            crit.add(fN);
//        }
//        if (!lastName.isEmpty()) {
//            lN = Restrictions.ilike("lastName", lastName, MatchMode.ANYWHERE);
//            crit.add(lN);
//        }
//        if (!telNumber.isEmpty()) {
//            tN = Restrictions.ilike("contactTelDetails.telNumber", telNumber, MatchMode.ANYWHERE);
//            crit.add(tN);
//        }


        if (!sSearch_r.isEmpty() && sSearch_r != null) {
            String str = URLEncoder.encode(sSearch_r, "UTF-8");
            String sSearch = URLDecoder.decode(str, "UTF-8");
            fN = Restrictions.like("firstName", sSearch, MatchMode.ANYWHERE).ignoreCase();
            lN = Restrictions.like("lastName", sSearch, MatchMode.ANYWHERE).ignoreCase();
            crit.add(Restrictions.or(fN, lN));

            //crit.add(lN);
        }


        //Criteria criteria = session.createCriteria(Contact.class).createAlias("contactTelDetails", "contactTelDetails").add(Restrictions.ilike("firstName", firstName, MatchMode.ANYWHERE)).add(Restrictions.ilike("lastName",lastName, MatchMode.ANYWHERE)).add(Restrictions.ilike("contactTelDetails.telType",telType,MatchMode.ANYWHERE)).add(Restrictions.ilike("contactTelDetails.telNumber",telNumber,MatchMode.ANYWHERE));

//        crit.setResultTransformer(DistinctRootEntityResultTransformer.INSTANCE);

//        crit.setResultTransformer(DistinctRootEntityResultTransformer.INSTANCE);
//        crit.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);

        if (firstRes != 0) {
            crit.setFirstResult(firstRes - 1);
        }
        if (maxRes != 0) {
            crit.setMaxResults(maxRes);
        }


        List<Contact> contacts = crit.list();
//        List<Contact> contacts = crit.createAlias("contactTelDetails", "contactTelDetails").list();

        sort(contacts);
        return contacts;
    }

    void sort(List<Contact> contacts) {
        Comparator<ContactTelDetail> byTypeNumber = new TelTypeComparator();
        for (Contact c : contacts) {
            List<ContactTelDetail> contactTelDetails = c.getContactTelDetails();
            Collections.sort(contactTelDetails, byTypeNumber);
        }
    }

    class TelTypeComparator implements Comparator<ContactTelDetail> {


        /*   public int compare(ContactTelDetail det1, ContactTelDetail det2) {
       int comp = det2.getTelType().length() - det1.getTelType().length();
       if (comp != 0) {
           //... If different lengths, we're done.
           return comp;
       } else {
           //... If equal lengths, sort alphabetically.
           return det1.getTelNumber().compareToIgnoreCase(det2.getTelType());
       }
   }     */
        public int compare(ContactTelDetail det1, ContactTelDetail det2) {
//            int comp = det2.getTelType().length() - det1.getTelType().length();
//            if (comp != 0) {
//                //... If different lengths, we're done.
//                return comp;
//            } else {
//                //... If equal lengths, sort alphabetically.
            return det1.getTelType().compareToIgnoreCase(det2.getTelType());
//            }
        }
    }

}


